
#include <cstdio>
#include <BOpenGL>
#include <BPainter>
#include <BImage>
#include <BCamera>

#include <BTexture>
#include "member_BTexture.h"
#include "member_BImage.h"

using namespace BWE;

#define member					(*(member_BTexture*)_ptr)
#define member_allocate()		_ptr = new member_BTexture(this)
#define member_release()		delete (member_BTexture*)_ptr

BTexture::BTexture()
{
	member_allocate();
	setWrap(Wrap_Clamp);
	setBlend(Blend_Replace);
	setFilter(Filter_Linear);
}
BTexture::~BTexture()
{
	if (member.tbo)
	{
		BOpenGL::ReleaseTextureObject(member.tbo);
		member.tbo = 0;
	}
	member_release();
}

void BTexture::setBlend(Blend blend)
{
	if (member.blend != blend)
	{
		member.blend = blend;
		member.dirty = true;
	}
}
BTexture::Blend BTexture::blend() const
{
	return member.blend;
}

void BTexture::setBlendColor(const BColor& color)
{
	if (member.blendColor != color)
	{
		member.blendColor = color;
		member.dirty = true;
	}
}
const BColor& BTexture::blendColor() const
{
	return member.blendColor;
}

void BTexture::setFilter(Filter filter)
{
	if (member.filter != filter)
	{
		member.filter = filter;
		member.dirty = true;
	}
}
BTexture::Filter BTexture::filter() const
{
	return member.filter;
}

void BTexture::setWrap(Wrap wrap)
{
	if (member.wrap != wrap)
	{
		member.wrap = wrap;
		member.dirty = true;
	}
}
BTexture::Wrap BTexture::wrap() const
{
	return member.wrap;
}

void BTexture::setMipmap(bool enabled)
{
	if(member.mipmap != enabled)
	{
		member.mipmap = enabled;
		member.dirty = true;
	}
}
bool BTexture::mipmap() const
{
	return member.mipmap;
}

bool BTexture::bind() const
{
	if (member.tbo == 0)
	{
		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
		glGenTextures(1, &member.tbo);
	}
	if (member.dirty && member.tbo)
	{
		member.dirty = false;
		glBindTexture(GL_TEXTURE_2D, member.tbo);

		if (member.blend == BTexture::Blend_Modulate)
			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
		if (member.blend == BTexture::Blend_Replace)
			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
		if (member.blend == BTexture::Blend_Decal)
			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
		if (member.blend == BTexture::Blend_Color)
		{
			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
			glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat*)&member.blendColor);
		}

		if (member.filter == Filter_Linear)
		{
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		}
		if (member.filter == Filter_Nearest)
		{
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		}

		if (member.wrap == Wrap_Clamp)
		{
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
		}
		if (member.wrap == Wrap_Repeat)
		{
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		}

		if (member.mipmap)
		{
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4);
			if (member.filter == Filter_Linear)
			{
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
			}
			if (member.filter == Filter_Nearest)
			{
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_NEAREST);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
			}
		}

		glBindTexture(GL_TEXTURE_2D, 0);
	}
	return true;
}

bool BTexture::unbind() const
{
	if (member.tbo)
	{
		glBindTexture(GL_TEXTURE_2D, 0);
		return true;
	}
	return false;
}

